package model;

import java.util.HashSet;
import java.util.Set;

import model.enums.Classroom;
import persistency.writer.Writable;
import util.TimeBlock;

/**
 * OfferedCourse.java
 * Purpose: this class represents a course that is being offered to students by the school
 * 
 * @author Hans Brems
 * @version 1.0 03/11/2011
 */

public class OfferedCourse implements Writable, Cloneable, Comparable<OfferedCourse> {

	private Classroom classroom;
	private Course course;
	private int numberOfPlaces;
	private Set<Registration> registrations;
	private Teacher teacher;
	private TimeBlock timeBlock;
	private static int offeredCourseCounter = 0;
	private int primaryKey;
	
	/** Constructs a new offered course object */
	public OfferedCourse() {
		this.classroom = Classroom.UNASSIGNED;
		this.course = null;
		this.registrations = new HashSet<Registration>();
		this.teacher = null;
		this.timeBlock = null;
		primaryKey = offeredCourseCounter++;
	}
	
	/** Constructs a new offered course object */
	public OfferedCourse(Classroom classroom, Course course, int numberOfPlaces,
			Teacher teacher, TimeBlock timeBlock) {
		this.classroom = classroom;
		this.course = course;
		this.numberOfPlaces = numberOfPlaces;
		this.registrations = new HashSet<Registration>();
		this.teacher = teacher;
		this.timeBlock = timeBlock;
		primaryKey = offeredCourseCounter++;
	}

	/** Returns the classroom in which the course is held **/
	public Classroom getClassroom() {
		return classroom;
	}

	/** Sets the classroom in which the course is held 
	 * @throws Exception **/
	public void setClassroom(Classroom classroom) throws Exception {
		if(classroom != Classroom.UNASSIGNED){
			this.classroom = classroom;
		}else{
			throw new Exception("Unassigned isn't a valid value for classroom.");
		}
	}

	/** Returns the course which is being offered **/
	public Course getCourse() {
		return course;
	}

	/** Sets the course which is being offered **/
	public void setCourse(Course course) {
		this.course = course;
	}

	/** Returns the maximum number of students that can follow the course at one time **/
	public int getNumberOfPlaces() {
		return numberOfPlaces;
	}

	/** Sets the maximum number of students that can follow the course at one time **/
	public void setNumberOfPlaces(int numberOfPlaces) {
		this.numberOfPlaces = numberOfPlaces;
	}

	/** Returns the registrations which have been made for this offering **/
	public Set<Registration> getRegistrations() {
		return registrations;
	}

	/** Sets the registrations which have been made for this offering **/
	public void setRegistrations(Set<Registration> registrations) {
		this.registrations = registrations;
	}
	
	/** Returns the teacher that is teaching the course **/
	public Teacher getTeacher() {
		return this.teacher;
	}
	
	/** Sets the teacher that is teaching the course **/
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	
	/** Returns the time block in which the course is scheduled **/
	public TimeBlock getTimeBlock() {
		return this.timeBlock;
	}
	
	/** Sets the time block in which the course is scheduled **/	
	public void setTimeBlock(TimeBlock timeBlock) {
		this.timeBlock = timeBlock;
	}

	/** Checks for equality with another object **/
	@Override
	public boolean equals(Object object) {
		
		OfferedCourse otherOfferedCourse;
		
		// Check for same reference
		if (this == object) {
			return true;
		}
		
		// Check if object type is equal
		if (object == null || object.getClass() != this.getClass()) {
			return false;
		}
		
		// Cast object to correct class
		otherOfferedCourse = (OfferedCourse)object;
		
		// Check if object properties are equal
		return otherOfferedCourse.getClassroom().equals(this.classroom) &&
				otherOfferedCourse.getCourse().equals(this.course) &&
				otherOfferedCourse.getNumberOfPlaces() == this.numberOfPlaces &&
				otherOfferedCourse.getRegistrations().equals(this.registrations) &&
				otherOfferedCourse.getTeacher().equals(this.teacher) &&
				otherOfferedCourse.getTimeBlock().equals(this.timeBlock);
	}
	
	
	
	/** Returns a string representation of the object **/
	@Override
	public String toString() {
		return String.format("%d. %s (%s)",primaryKey, this.course.getName(), this.classroom);
		//return this.course.getName();
	}

	/** Clones the object **/
	@Override
	public Object clone() throws CloneNotSupportedException {
		
		// Copy parent
		OfferedCourse clone = (OfferedCourse)super.clone();
		
		// Set properties
		clone.classroom = this.classroom;
		clone.course = this.course;
		clone.numberOfPlaces = this.numberOfPlaces;
		clone.registrations = this.registrations;
		clone.teacher = this.teacher;
		clone.timeBlock = this.timeBlock;
		
		// Return result
		return clone;
	}	

	/** Compares the object to another object **/
	public int compareTo(OfferedCourse offeredCourse) {
		return 0;
	}

	@Override
	public String toDataString() {
		return  course.getCode() + "\t" + classroom.ordinal() + "\t"
				+ teacher.getTeacherCode() + "\t" + numberOfPlaces + "\t"
				+ timeBlock.getFormattedString() + "\n";
	}
	
	@Override
	public Object getPrimaryKey(){
		return primaryKey;
	}

	public void setPrimaryKey(int primaryKey) {
		this.primaryKey = primaryKey;
	}
	
	
}